perm filename FONT1.TXT[MF,DEK] blob
sn#752802 filedate 1984-05-03 generic text, type T, neo UTF8
Computer homework #2: Strokes and curves.
In this assignment the class is going to create a new "typeface" that
will be known as the CS279 Font, Opus 1. Each student should write a
program for one uppercase letter and one lowercase letter;
the last page of this handout contains a tentative list that shows
who is responsible for which characters.
The following rules and regulations must be observed so that (a) there
will be at least some consistency, and (b) we will have a good excuse for
not doing as well as Baskerville and Bodoni did.
Rule 1. All characters must be made from shapes produces by either the
"stroke" or the "curve" routine supplied in file font1base.mf.
(Both routines will be explained later in this handout.) The idea is to
strive for letters that are as attractive as possible, subject to this
constraint, without using those routines in unusually complicated ways.
Rule 2. The stroke widths should be based on parameters called thickwidth
and thinwidth. (This will be illustrated below.)
Rule 3. The character sizes should be based on several additional parameters:
capheight = height of uppercase letters
xheight = height of lowercase x
ydepth = depth of lowercase y
hheight = height of lowercase h
em = width of uppercase M
We will be generating three fonts of type from the class design:
`normal' (N), `bold' (B), and `bold extended' (BX). In the B and BX fonts,
thinwidth will be slightly larger than it is in the N font, and thickwidth
will be considerably larger. The size measurements will be the same in all
three fonts except that the xheight and the em will be a little larger in
the BX version. You should design your letters so that they look decent
with all three settings of the parameters. (Later, we'll try other values
of thickwidth, thinwidth, capheight, etc., just to see what happens; but
you needn't worry too much about having your design work properly except
for the three sets of values that the font1base.mf file supplies.)
Rule 4. Your solution to this problem should be entered into a file
called "font1.mf", in your directory. It should have the same form
as the example solution below. (The grader will look at it and use
it to make up the final fonts, with which we hope to set some text!)
As you work on this problem you'll realize that it is impossible to
design good letterforms in isolation; you'll want to know much more
about the other letters, and you'll want to see how the shapes work in
combination when they make words, etc. Therefore it is clear that
we won't be able to make a high-quality typeface with our first
attempt. This is as it should be, since we are just doing our
first practice exercises with a new tool; we shouldn't expect perfection
immediately! Nor should we be afraid to make mistakes.
However, in order to make the exercise as instructive as
possible, let's try to do the best we can, under the circumstances.
"Pen positions."
The stroke and curve routines that we shall use deal with so-called
pen positions, which tend to resemble the behavior of an idealized
broad-edge pen.
Pen position 1 corresponds to three METAFONT points z1, z1l, and z1r;
pen position 2 corresponds to the three points z2, z2l, z2r; and so on.
The idea is that z1 represents the center of a wide, flat pen nib that is
being held in a certain position; z1l and z1r represent its left and right
ends. We shall specify the distance between z1l and z1r (i.e., the width
of the pen) and the angle of inclination.
Angles are measured with respect to a horizontal line that points to the right.
Thus, a pen angle of 0 means that z1r is directly to the right of z1l,
while an angle of 90 puts z1r directly above; an angle of 45 would be
called "northeast" on a map. An angle of -90 puts z1r directly below z1l,
and an angle of -45 would be called "southeast" on a map. An angle of 180
actually puts z1r to the left of z1l; so does an angle of -180.
Thus, pen position 1 involves six numbers: x1, y1, x1l, y1l, x1r, and y1r.
But you have to specify only four things in order to specify a pen position:
the length, the angle, one of the x's, and one of the y's. The length and
angle are specified by saying
pos <number> (<length>, <angle>);
the x's and y's are specified by equations as usual. For example, consider
z1=(3,5); pos1(20,30);
this defines pen position 1 so that the pen is centered at point (3,5),
it is 20 pixels wide, and it is inclined at an angle of 30 degrees.
Consider also the commands
y2=0; x2l=10; pos2(20,45);
they specify pen position 2 so that its center occurs at the baseline
(i.e., at the line of points whose y coordinate is zero) and its left
edge has an x-coordinate of 10. The pen is 20 pixels wide and inclined 45.
It turns out that "pos2(20,45)" is an abbreviation for four equations
by which METAFONT is able to figure out the appropriate values of
the other coordinates x2, y2l, x2r, and y2r.
[Indeed, if you were running METAFONT with "tracingequations:=1", as in
last week's lecture, the computer would type
## y2=0
## x2l=10
## y2l=-y2r
## x2=0.5x2r+5
## y2r=7.07108
#### y2l=-7.07108
## x2r=24.14215
#### x2=17.07108
at you. Thus z2l=(10,-7.07), z2=(17.07,0), and z2r=(24.14,7.07).
If you plot these points, you'll see that they do satisfy the stated
conditions; we happily let the machine do the arithmetic.]
"Strokes."
A stroke is, basically, a straight line between two pen positions.
However, the stroke can also taper in the middle, as if you were
easing up a little on the pressure as you drew this line with a
broad-edge pen. This makes the stroke a bit more interesting.
For example, here's a stroke that was drawn with the command
"stroke (1,2,.3,.4,.1)":
In general the command is
stroke(i,j,<taper location>,<left taper>,<right taper>)
where i and j are the starting and ending positions; the taper
location is a fraction saying how much of the way between i and j
is the point of maximum taper (minimum thickness); and the left and
right taper amounts are fractions indicating how much of the width is
lost on the l and r sides of the stroke.
More precisely, METAFONT draws a stroke by making the following
construction, assuming that i=1 and j=2:
(1) Connect z1l and z2l, z1 and z2, z1r and z2r by straight lines.
(2) Let z.l=t[z1l,z2l], z=t[z1,z2], z.r=t[z1r,z2r], where t is the
taper location. (In other words, go t of the way along the
lines constructed in step (1).) These three points will lie
on a straight line.
(3) Let zz.l=lt[z.l,z] and zz.r=rt[z.r,z], where lt and rt are the
left and right taper amounts. (In other words, go lt of the way
from z.l to z, and rt of the way from z.r to z, obtaining
two new points zz.l and zz.r.)
(4) Now fill the stroke, by going from z1l to z2l via zz.l, then
straight to z2r, then from z2r to z1r via zz.r, then straight to z1l.
The direction of the curves at the taper points zz.l and zz.r is chosen
just as the direction of the "arc" routine was chosen in the previous
homework assignment; i.e., it will be in the direction of the straight
line that would have been drawn if there were no taper.
If t=0, however, points zz.l and zz.r are omitted, and the stroke
consists entirely of straight lines.
"Curves."
A curve is something like the arc routine in the previous homework;
it is defined by three pen positions. For example, here is a curve
that was drawn with the command "curve(1,2,3)":
The direction at z2l is the same as the direction of a straight line
from z1l to z3l; the direction at z2r is similar.
In order to use curves and strokes in combination, without jerks
where two of them come together, it's also desirable to be able to
specify the directions at the endpoints (e.g., at z1 and z3). For
this purpose you can say, for example,
dz1=(1,0); dz3=(0,-1)
if you want the curve to be traveling rightward at pen position 1
and downward at pen position 2.
The stroke and curve routines will respect the given directions, if
"dz" has been specified; otherwise they will give METAFONT's normal
curl at the endpoints.
The form of your file.
For this homework assignment, your file "font1.mf" should look like this:
(The example assumes that your letters are "A" and "a"; you should
of course replace this by the two letters that you're really doing.)
input font1base % read in the special routines for this problem
proofing:=1; % this will make a "GF" output file
% so you can get hardcopy proofs and/or run "bits"
vardef char.A =
setwidth .6em; % do this first; it sets the character width
<equations for pen positions>
<stroke and/or curl commands>
labelpos( <list all the pen positions you have defined> );
enddef;
vardef char.a =
setwidth .5em; % of course, you should choose the width you want
<equations for pen positions>
<stroke and/or curl commands>
labelpos( <list all the pen positions you have defined> );
enddef;
test.normal(char.A); % this will display your A, with "normal" parameters
test.bold(char.A); % and this will display it with "bold" parameters
test.boldx(char.A); % and bold extended
test.normal(char.a);
test.bold(char.a);
test.boldx(char.a); % likewise for the a
test(char.A); % this shows all three A's, but only half size
test(char.a); % all three a's
end
[Thus, the "test" routine allows you to test the way changes to your
program affect all three character definitions; the "test.normal",
"test.bold", and "test.boldx" routines show you one parameter setting
at a time, enlarged.]
Note: The "setwidth" routine in font1base sets variable w to the
width of the current character. You might find it useful to use
w in your equations for the pen positions, as in the examples that
follow. Then you can easily modify your character to make it
wider or narrower, by simply changing the setwidth command.
Sample program: Lowercase l.
For example, here's a letter that consists of just two pen positions
and just one stroke:
vardef char.l =
setwidth 1/3em; % character width is one third of an em
pos1(1.5thickwidth,45); % the pen is "thicker than thick" at the top
pos2(1.05thickwidth,10); % and also slightly flared at the bottom
z2=(.5w,0); % at the baseline, midway between left and right ends
y1=hheight; x1r=x2r; % at the hheight, aligned at the right with pos2
stroke(1,2,.1,.2,0); % taper at the left but not the right
labelpos(1,2);
enddef;
The drawings below show how this construction looks with the three different
settings of the parameters. This particular letter doesn't change in the
case of "bold extended", except to have slightly more blank space at the
sidebars, because there's only one stroke and because the larger
xheight in boldx doesn't affect "l".
The examples here and on the next page attempt to give some indication
of a kind of font that is somehow suited to the "stroke" and "curve"
constraints. A font without serifs, and with an informal asymmetric feeling,
is indicated. It would be nice to carry features of the design above
into other letters with similar features. For example, the sheared top
of the "l" calls for similar treatment at the top left of "b", "h", "k",
"m", "n", "p", "r", "u", and also at the top of the stems in "i", "j",
and possibly "d". The amount of white space at the left and right of the "l"
should be approximately the same at the left and right of other characters
that present a straight face to their neighbors (e.g., at the left of
"b" and "k"; at the right of "d", "i", and probably "h", "m", "n"). And so on.
Another sample program: Uppercase U.
Here's a more complex example, to be read after you thoroughly understand
the "l" program on the previous page. There are seven pen positions,
and the curious thing here is that METAFONT's crazy pen has to
turn upside down (with "left" and "right" effectively changing places)
as we go around the U. The reason for this is that the directions
where strokes join together have a definite left-rightness about them.
For example, the equation "dz4=(1,0)" says that we're moving to the
right at position 4. If we tried to continue after "curve(2,3,4)"
with "curve(6,5,4)" coming from the other side, METAFONT would try
to draw a curve that goes from 5 to 4 but ending in a rightward direction.
Thus, we should continue after curve(2,3,4) with curve(4,5,6). But
by then the pen has turned upside down. (It is possible to use METAFONT
in other ways, so as to imitate calligraphy in such a way that the pen
doesn't turn; but that's another story that we'll discuss later. The
curve routine in this homework calls for a pen that turns around.)
vardef char.U =
setwidth .75em;
pos1(1.1thickwidth,10); % the pen starts out slightly thick
pos2(thickwidth,10);
pos3(thickwidth,40);
pos4(.5[thickwidth,thinwidth],75);
pos5(.9[thickwidth,thinwidth],130);
pos6(thinwidth,180); % now it's "thin", and turned over
pos7(1.1thinwidth,190);
x1l=.1em; x7l=w-.1em; % there are sidebars of .1em
y1=y7=capheight; % we have now fully specified 1 and 7
x2=x1; y2=.3capheight; dz2=(0,-1); % going down at 2
x3=.75[x4,x2]; y3=.75[y2,y4]; % see below!
x4r=.5[x2r,x6r]; y4l=-.05capheight; dz4=(1,0);
x5=.71[x4,x6]; y5=.71[y6,y4]; % see below!
x6=x7; y6=1/3capheight; dz6=(0,1); % going up at 6
stroke(1,2,.2,.05,.05); % here we make a very slight taper
curve(2,3,4); curve(4,5,6); % curve the bottom
stroke(6,7,.8,.05,.05); % and finish somewhat as at the left
labelpos(1,2,3,4,5,6,7); % all positions should be listed
enddef;
The equations "x5=.71[x4,x6]; y5=.71[y6,y4]" make the curve from
4 to 5 to 6 pretty nearly a circle; notice that the x-coordinate
is specified as a fraction of the distance from x4 to x6, while the
y-coordinate is specified as a fraction of the distance from y6 to y4.
By making the fraction .75 instead of .71, at position, we obtain
a somewhat squarer curve from 2 to 3 to 4.
Proofsheets for the three U's.
Appendix: The base file.
Some people in the class can't wait to learn more details about METAFONT's
underlying language; hence the contents of file font1base.mf are shown here.
(You aren't supposed to be able to understand this, at least not yet!)
(The stroke and curve routines are complicated only because they have
"conditional" parts that are used only if certain dz directions are defined.)
delimiters (); % we always start with this!
smoothing:=1; autorounding:=2; % this adjusts curves to the raster
vardef z@# = (x@#,y@#) enddef;
vardef dz@# = (dx@#,dy@#) enddef;
edges e;
def fill expr x = addto e contour x withweight 1 enddef;
def shipit = if proofing>0: shipout e; fi enddef;
def showit = display e on window enddef;
vardef pos@#(expr length,theta) =
z@#=.5[z@#l,z@#r];
z@#r-z@#l=(length,0) rotated theta enddef;
def stroke(suffix $,$$)(expr t,lt,rt) =
fill z$l
if not unknown dz$: {dz$} fi
if t<>0: ..lt[ t[z$l,z$$l],t[z$,z$$] ]{z$$l-z$l} fi
.. z$$l
if not unknown dz$$: {dz$$} fi
& z$$l..z$$r
& z$$r
if not unknown dz$$: {-dz$$} fi
if t<>0: ..rt[ t[z$r,z$$r],t[z$,z$$] ]{z$r-z$$r} fi
.. z$r
if not unknown dz$: {-dz$} fi
& z$r..z$l & cycle;
showit; enddef;
def curve(suffix $,$$,$$$) =
fill z$l
if not unknown dz$: {dz$} fi
.. z$$l{if unknown dz$$: z$$$l-z$l else: dz$$ fi}
.. z$$$l
if not unknown dz$$$: {dz$$$} fi
& z$$$l..z$$$r
& z$$$r
if not unknown dz$$$: {-dz$$$} fi
.. z$$r{if unknown dz$$: z$r-z$$$r else: -dz$$ fi}
.. z$r
if not unknown dz$: {-dz$} fi
& z$r..z$l & cycle;
showit; enddef;
def autolabel = makelabel(" 5") enddef;
def makelabel(expr s)(text t) = forsuffixes $:=t: if not unknown z$:
special s&str$; numspecial x$; numspecial y$; fi endfor enddef;
def proofrule(expr a,b) =
special "rule"; numspecial xpart a; numspecial ypart a;
numspecial xpart b; numspecial ypart b enddef;
def labelpos(text t) =
if proofing>0:
forsuffixes $:=t: autolabel($l,$r,$); endfor fi enddef;
Appendix: File font1base.mf (continued).
def clear =
numeric x[],y[],x[]l,y[]l,x[]r,y[]r,dx[],dy[];
e:=nulledges;
enddef;
def setwidth expr x =
chardw:=x;
numeric w; w=chardw;
if proofing>0:
for n:=0 step .1em until chardw-1:
proofrule((n,-ydepth),(n,hheight)); endfor
proofrule((chardw,-ydepth),(chardw,hheight));
proofrule((0,-ydepth),(chardw,-ydepth));
proofrule((0,0),(chardw,0));
proofrule((0,xheight),(chardw,xheight));
proofrule((0,capheight),(chardw,capheight));
proofrule((0,hheight),(chardw,hheight));
fi
enddef;
vardef init.normal(expr f) =
begingroup
numeric thinwidth,thickwidth,capheight,xheight,hheight,ydepth,em;
thinwidth = 11f; thickwidth = 15f; em = 200f;
capheight = 130f; xheight = 90f; hheight = 140f; ydepth = 40f;
endgroup
enddef;
vardef init.bold(expr f) =
init.normal(f); thinwidth:= 14f; thickwidth:= 24f;
enddef;
vardef init.boldx(expr f) =
init.bold(f); xheight:=95f; em:= 220f;
enddef;
vardef test@#(text #)=
begingroup
if str @# = "": % test all three
openwindow 1 from (0,0) to (420,166) at (-20,310);
openwindow 2 from (0,167) to (420,333) at (-20,310);
openwindow 3 from (0,334) to (420,500) at (-20,310);
window:=1; init.normal(1); clear; #; "normal"; shipit;
window:=2; init.bold(1); clear; #; "bold"; shipit;
window:=3; init.boldx(1); clear; #; "boldx"; shipit;
else: openwindow 0 from (0,0) to (420,500) at (-40,310);
window:=0; init@#(2); clear; #; str @#; shipit;
fi;
endgroup
enddef;
Tentative assignment of letters to people:
A Ann Lasko-Harvill
B William Burley
C Peter Chu
D Dan Mills
E Joey Tuttle
F Pavel Curtis
G Jean-Luc Bonnetain
H John Hershberger
I Nori Tokusue
J Jennie Tan
K Dikran Karagueuzian
L Bruce Leban
M Eric Muller
N Dave Seigel
O Bruce Fleischer
P Michael Tchao
Q Neenie Billawala
R Renata Byl
S Abraham Bleiberg
T Theresa-Marie Rhyne
U Don Knuth
V Lov Grover
W Stan Osborne
X Alan Spragens
Y Arnie Olds
Z Malcolm Brown
a Ann Lasko-Harvill
b Dave Siegel
c Alan Spragens
d Jean-Luc Bonnetain
e Dan Mills
f Malcolm Brown
g Bruce Leban
h Arnie Olds
i Bruce Fleischer
j John Hershberger
k Renata Byl
l Don Knuth
m Dikran Karagueuzian
n Jennie Tan
o Stan Osborne
p Theresa-Marie Rhyne
q Pavel Curtis
r Peter Chu
s Eric Muller
t Abraham Bleiberg
u Nori Takusue
v Lov Grover
w Joey Tuttle
x William Burley
y Neenie Billawala
z Michael Tchao